feat(runner): complete Fleet enrollment and runner details (RUN-12, RUN-13) - #373
feat(runner): complete Fleet enrollment and runner details (RUN-12, RUN-13)#373KafuChino123 wants to merge 38 commits into
Conversation
Add a FleetControlClient Swift package with generated protobuf and gRPC stubs for the fleet agent local control API. Wire the local package into the ArcBox app target so phase 1 desktop integration can import the generated client types.
Wrap the generated fleet control stubs in a high-level client for lifecycle, state watch, and settings RPCs. Map proto responses into desktop-facing models while preserving optional settings update presence semantics, and cover the mapping behavior with tests.
Add the local fleet control client to SwiftUI environment values and app scene injection. Start the fleet control transport outside daemon startup, log through the fleet category, and close it during app termination.
Drive fleet agent state from the local control watch stream. Add lifecycle actions, settings updates, reconnect backoff, and user-readable error handling for the runners dashboard.
Consume the signed-in OIDC session to list Platform workspaces and issue workspace-scoped Fleet enrollment tokens. Wire token issuance into local Fleet Agent enrollment and configure the Platform endpoint for app and CI builds.
Replace RUN-9 sample data and stub actions with FleetViewModel watch snapshots, workspace enrollment, and local drain/resume controls. Expose the runner section in release builds and cover the presentation-state mapping.
Let ArcBoxTests consume FleetControlClient through the hosted ArcBox target, avoiding Xcode’s duplicate dynamic gRPC package graph. Handle runner item-selection deep links explicitly so navigation remains exhaustive.
- coordinate authenticated token handoff with local Agent state - keep Fleet watch and client transport app-scoped - reconcile unknown outcomes and graceful termination
On macOS 26, any state change inside a fixedSize(vertical: true) subtree triggers a window-sizing pass that resizes the window — or the NavigationSplitView content when the window cannot grow — to the screen's visible-frame height, sliding the sidebar under the title bar and pushing the account button off-screen. Drop the modifier from the dynamic error label (it wraps identically without it) and document the pitfall in AGENTS.md.
Replace the OIDC Authorization Code + PKCE flow with the Better Auth device-authorization grant: request a device code, open the approval page in the default browser, and poll the token endpoint per RFC 8628. The polled access token is an opaque Better Auth session token with a sliding server-side expiry, sent as the platform API bearer — the token the platform actually accepts, unblocking fleet enrollment token issuance. Identity now comes from the provider session endpoint instead of OIDC userinfo/ID-token claims, and sign-out revokes the session server-side. The Keychain store self-heals by clearing pre-device-flow token blobs. PKCE, discovery, code exchange, token refresh, and the custom-scheme OAuth callback (including its DeepLinkRouter leg) are gone; build configuration keys are unchanged. The Account pane and runner section show the confirmation code with reopen-browser and cancel affordances while approval is pending.
Use an ephemeral cookie-free URLSession for Better Auth requests and remove legacy Better Auth cookies persisted by previous builds. Add regressions covering session configuration, response cookie isolation, and scoped legacy cookie cleanup.
Prevent concurrent device sign-in tasks, expose recovery for terminal Fleet states, and complete the test-target and cancellation cleanup validated by the full app suite.
…hots Credential-rejected and detached snapshots ignored loadState, so a disconnected watch still offered the unenroll recovery action against a stale snapshot. Extract the unenrolled branch's loadState switch into connectivityOverride and reuse it for all three terminal cases.
…-auth # Conflicts: # ArcBox.xcodeproj/project.pbxproj # ArcBox/App/AppDelegate.swift # ArcBox/App/DeepLinkRouter.swift # ArcBox/ArcBoxApp.swift # ArcBox/Info.plist # ArcBox/Models/NavItem.swift # ArcBox/Views/Settings/AccountSettingsView.swift # ArcBox/Views/Settings/SettingsView.swift # ArcBox/Views/SidebarAccountButton.swift # Packages/ArcBoxAuth/Sources/ArcBoxAuth/Session/AuthSession+SignIn.swift # Packages/ArcBoxAuth/Tests/ArcBoxAuthTests/AuthSessionTests.swift
…eat/run-12-13-runner-details # Conflicts: # ArcBox.xcodeproj/project.pbxproj # ArcBox/Views/ContentView.swift
Greptile SummaryThis PR replaces the previous authentication and manual runner paths with device authorization, Fleet Agent enrollment/watch state, Fleet Platform-backed runner details, and a complete This Mac runner interface.
Confidence Score: 4/5The PR should not merge until runner job history can retrieve or expose pages beyond the first 50 results. The platform response cursor is saved but never consumed, so machines with more than 50 jobs always present incomplete history despite the API explicitly returning additional-page state. Files Needing Attention: ArcBox/ViewModels/RunnerPlatformStore.swift
|
| Filename | Overview |
|---|---|
| Packages/ArcBoxAuth/Sources/ArcBoxAuth/Session/AuthSession.swift | Replaces OIDC token refresh state with Better Auth session restoration, verification, and sign-out behavior. |
| ArcBox/ViewModels/Fleet/FleetEnrollmentCoordinator.swift | Implements the enrollment state machine, cancellation boundaries, post-handoff reconciliation, and recovery states. |
| ArcBox/ViewModels/Fleet/FleetViewModel.swift | Owns Fleet Agent status, reconnecting snapshot watch, mutations, and image-preparation state. |
| ArcBox/ViewModels/RunnersViewModel.swift | Composes authentication, enrollment, live Fleet state, and runner-facing actions into UI state. |
| ArcBox/ViewModels/RunnerPlatformStore.swift | Polls platform host and job data safely across overlapping refreshes, but permanently truncates job history to the first 50 records. |
| Packages/FleetPlatformClient/Sources/FleetPlatformClient/FleetPlatformClient.swift | Adds authenticated Fleet Platform requests with typed response and HTTP error handling. |
| ArcBox/Services/FleetAgentConnection.swift | Manages the local Fleet Agent transport and exposes readiness to runner enrollment. |
| ArcBox/Views/Runners/RunnersView.swift | Adds the main runner list/detail experience and ties platform polling to enrolled machine state. |
| ArcBox/App/ApplicationCoordinator.swift | Wires authentication, Fleet clients, runner state, hosted roots, startup, and shutdown together. |
Sequence Diagram
sequenceDiagram
participant User
participant Desktop as ArcBox Desktop
participant Auth as Better Auth
participant Platform as Fleet Platform
participant Agent as Local Fleet Agent
User->>Desktop: Sign in
Desktop->>Auth: Request device authorization
Auth-->>Desktop: User code and verification URL
Desktop->>Auth: Poll for session
Auth-->>Desktop: Session token
Desktop->>Platform: Resolve workspaces and machine
Desktop->>Agent: Enroll using platform-issued token
Agent-->>Desktop: Stream current runner snapshots
Desktop->>Platform: Fetch machine details and first job page
Platform-->>Desktop: Host, jobs, and next cursor
Desktop-->>User: Runner status and details
Reviews (1): Last reviewed commit: "Merge remote-tracking branch 'origin/fea..." | Re-trigger Greptile
| cursor: nil, | ||
| limit: 50 |
There was a problem hiding this comment.
When a runner has more than 50 historical jobs, loadSnapshot() always requests cursor: nil and never consumes the returned nextCursor, causing every job after the first page to remain inaccessible.
Knowledge Base Used: ViewModels: MVVM State Layer
Summary
Why
RUN-12 and RUN-13 require live Platform and Agent state before host and job details can be presented meaningfully. This change lands the complete dependency chain from authentication through enrollment and Fleet watch state, replacing the earlier sample and manual-enrollment paths.
User impact
Signed-in users can connect this Mac to an ArcBox workspace, monitor runner readiness and recovery states, drain or unenroll the runner, inspect host identity and capacity, browse job history, and open the corresponding GitHub Actions details and logs.
Validation
make lintmake test— 294 XCTest tests and 70 Swift Testing tests passed with zero failures